package com.twotwoshop.service.chat.websocket;


import cn.hutool.json.JSONUtil;
import com.twotwoshop.commom.chat.MessageType;
import com.twotwoshop.domin.chat.pojo.ChatMessage;
import com.twotwoshop.domin.chat.vos.MessageResponse;
import com.twotwoshop.service.chat.service.ChatService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.time.Instant;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * WebSocket服务
 */
@Component
@ServerEndpoint("/ws/{sid}")//与controller相同通过路径进行匹配
@Slf4j
public class WebSocketServer {

    //存放会话对象
    private static Map<String, Session> sessionMap = new HashMap();

    private static ChatService chatService;

    // 注入ChatService的静态方法
    @Autowired
    public void setChatService(ChatService service) {
        WebSocketServer.chatService = service;
    }

    /**
     * 连接建立成功调用的方法
     */
    @OnOpen//加上这个注解 方法就变成了回调方法
    public void onOpen(Session session, @PathParam("sid") String sid) {
        log.info("客户端：" + sid + "建立连接");
        sessionMap.put(sid, session);
    }



    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String message, @PathParam("sid") String sid) {
        log.info("收到来自客户端：" + sid + "的信息:" + message);

        try {
            // 解析消息为MessageResponse格式
            MessageResponse messageResponse = JSONUtil.toBean(message, MessageResponse.class);
            if (messageResponse == null) {
                log.error("消息格式错误");
                return;
            }

            // 根据消息类型处理
            switch (messageResponse.getType()) {
                case AUTH:
                    handleAuth(sid, messageResponse.getData());
                    break;
                case CHAT:
                    handleChat(sid, messageResponse.getData());
                    break;
                case HEARTBEAT:
                    handleHeartbeat(sid);
                    break;
                default:
                    log.warn("未知的消息类型: {}", messageResponse.getType());
            }
        } catch (Exception e) {
            log.error("处理消息失败", e);
        }
    }

    /**
     * 处理认证消息
     */
    private void handleAuth(String sid, Object data) {
        try {
            Map<String, Object> authData = (Map<String, Object>) data;
            // 发送认证成功响应
            MessageResponse response = MessageResponse.builder()
                    .type(MessageType.ACK)
                    .data("认证成功")
                    .success(true)
                    .timestamp(System.currentTimeMillis())
                    .build();
            sendMessage(sid, JSONUtil.toJsonStr(response));
        } catch (Exception e) {
            log.error("认证失败", e);
        }
    }

    /**
     * 处理聊天消息
     */
    private void handleChat(String sid, Object data) {
        try {
            ChatMessage chatMessage = JSONUtil.toBean(JSONUtil.toJsonStr(data), ChatMessage.class);
            
            // 保存消息到数据库
            if(chatService != null) {

                //文本消息
                chatMessage.setType(0);
                chatMessage.setCreateTime(Date.from(Instant.now()));
                chatMessage.setIs_visible(true);
                chatService.save(chatMessage);
            }

            String receiverId = chatMessage.getReceiverId().toString();
            Session receiverSession = sessionMap.get(receiverId);

            if (receiverSession != null && receiverSession.isOpen()) {
                MessageResponse response = MessageResponse.builder()
                        .type(MessageType.CHAT)
                        .data(chatMessage)
                        .success(true)
                        .timestamp(System.currentTimeMillis())
                        .build();
                receiverSession.getBasicRemote().sendText(JSONUtil.toJsonStr(response));
            }
        } catch (Exception e) {
            log.error("发送消息失败", e);
        }
    }

    /**
     * 处理心跳消息
     */
    private void handleHeartbeat(String sid) {
        MessageResponse response = MessageResponse.builder()
                .type(MessageType.HEARTBEAT)
                .success(true)
                .timestamp(System.currentTimeMillis())
                .build();
        sendMessage(sid,JSONUtil.toJsonStr(response));
    }

    /**
     * 连接关闭调用的方法
     *
     * @param sid
     */
    @OnClose
    public void onClose(@PathParam("sid") String sid) {
        log.info("连接断开:" + sid);
        sessionMap.remove(sid);
    }

    /**
     * 群发
     *
     * @param message
     */
    public void sendToAllClient(String message) {
        Collection<Session> sessions = sessionMap.values();
        for (Session session : sessions) {
            try {
                //服务器向客户端发送消息
                session.getBasicRemote().sendText(message);
                System.out.println("websocket发送成功");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }



    /**
     * 发送消息给指定客户端
     */
    public void sendMessage(String sid, String message) {
        Session session = sessionMap.get(sid);
        if (session != null && session.isOpen()) {
            try {
                session.getBasicRemote().sendText(message);
                log.info("发送消息到客户端 {} 成功", sid);
            } catch (IOException e) {
                log.error("发送消息失败: {}", e.getMessage());
            }
        } else {
            log.warn("客户端 {} 不在线", sid);
        }
    }


    /**
     * 发送成功回执
     */
    private void sendSuccess(String sid, Long messageId) {
        MessageResponse response = MessageResponse.builder()
                .type(MessageType.ACK)
                .data(messageId)
                .success(true)
                .timestamp(System.currentTimeMillis())
                .build();

        sendMessage(sid, JSONUtil.toJsonStr(response));
    }

    /**
     * 发送错误消息
     */
    private void sendError(String sid, String errorMessage) {
        MessageResponse response = MessageResponse.builder()
                .type(MessageType.ERROR)
                .data(errorMessage)
                .success(false)
                .timestamp(System.currentTimeMillis())
                .build();

        sendMessage(sid, JSONUtil.toJsonStr(response));
    }


}
